﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Data.SqlClient;
using System.Data;
using TSL_Tools.SqlTools;
using ReportingEngine;
using System.IO;
using System.Windows.Forms.DataVisualization.Charting;
using System.Xml;
using System.ComponentModel;

namespace ReportGenerator
{
    public partial class TSL_ReportGenerator
    {

        #region -- Summary Report Info --------------------------------------------------
        public FlowDocument BuildRunSummaryAsFlowDocument(int runId, string templateName, bool usePerfmonValues)
        {
            using (StreamReader sr = new StreamReader(templateName))
            {
                string str = sr.ReadToEnd();

                Dictionary<string, string> timings = re.GetSummaryTimingResultsForReport(runId, usePerfmonValues);
                str = re.listOfRuns[runId].UpdateMainReportStringWithValues(str, timings);

                System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
                MemoryStream ms = new MemoryStream(encoding.GetBytes(str));

                FlowDocument fd = new FlowDocument();
                TextRange text = new TextRange(fd.ContentStart, fd.ContentEnd);
                text.Load(ms, DataFormats.Xaml);

                return fd;
            }
        }

        public string BuildRunSummaryAsFlowDocumentString(int runId, string templateName, bool usePerfmonValues)
        {
            using (StreamReader sr = new StreamReader(templateName))
            {
                string str = sr.ReadToEnd();

                Dictionary<string, string> timings = re.GetSummaryTimingResultsForReport(runId, usePerfmonValues);
                return re.listOfRuns[runId].UpdateMainReportStringWithValues(str, timings);
            }
        }
        #endregion

        #region -- Charting Routines ----------------------------------------------------
        public void AddChartToReport(Chart chart)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                chart.SaveImage(ms, System.Windows.Forms.DataVisualization.Charting.ChartImageFormat.Png);
                System.Drawing.Bitmap bm2 = new System.Drawing.Bitmap(ms);
                bm2.SetResolution(300, 300);
                using (MemoryStream ms2 = new MemoryStream())
                {
                    bm2.Save(ms2,System.Drawing.Imaging.ImageFormat.Png);

                    BitmapImage bi = new BitmapImage();
                    bi.BeginInit();
                    bi.CacheOption = BitmapCacheOption.OnLoad;
                    bi.StreamSource = ms2;
                    bi.EndInit();

                    System.Windows.Controls.Image _image = new System.Windows.Controls.Image();
                    _image.Source = bi;
                    _image.HorizontalAlignment = HorizontalAlignment.Left;
                    _image.Stretch = Stretch.None;
                    _image.Width = bi.Width;
                    _image.Height = bi.Height;


                    Paragraph paragraph = new Paragraph();
                    paragraph.Inlines.Add(_image);

                    // Create a document and add this paragraph.
                    fd.Blocks.Add(paragraph);
                }
            }

        }

        #endregion

        #region -- Table Routines -------------------------------------------------------
        public static FlowDocument CreateXamlTableFromDataTable(string tableTitle, DataTable dataTable, List<int> columnWidths, Typeface font, int fontSize, CellHighlighting highlighting, int minColumnWidth = 50, int maxColumnWidth = 350)
        {
            FlowDocument flowDoc = new FlowDocument();
            Table table1 = new Table();
            flowDoc.Blocks.Add(table1);

            int currentRowNumber = 0;
            ThicknessConverter tc;
            int numberOfColumns;
            TableRow currentRow = new TableRow();

            SetTableAndColumnProperties(dataTable, fontSize, minColumnWidth, font, table1, out tc, out numberOfColumns, columnWidths);

            if (tableTitle != "")
                AddHeaderRowToXamlTable(ref currentRow, tableTitle, fontSize, table1, ref currentRowNumber, numberOfColumns);

            AddColmnHeaderRowToXamlTable(dataTable, fontSize, table1, ref currentRowNumber, tc, ref currentRow);

            AddDataRowsToXamlTable(dataTable, fontSize, table1, ref currentRowNumber, tc, ref currentRow, highlighting);
            return flowDoc;
        }

        public static FlowDocument CreateXamlTableFromDataTable(string tableTitle, DataTable dataTable, List<int> columnWidths, Typeface font, int fontSize, int minColumnWidth = 50, int maxColumnWidth = 350)
        {
            FlowDocument flowDoc = new FlowDocument();
            Table table1 = new Table();
            flowDoc.Blocks.Add(table1);

            int currentRowNumber = 0;
            ThicknessConverter tc;
            int numberOfColumns;
            TableRow currentRow = new TableRow();

            SetTableAndColumnProperties(dataTable, fontSize, minColumnWidth, font, table1, out tc, out numberOfColumns, columnWidths);

            if (tableTitle != "")
                AddHeaderRowToXamlTable(ref currentRow, tableTitle, fontSize, table1, ref currentRowNumber, numberOfColumns);

            AddColmnHeaderRowToXamlTable(dataTable, fontSize, table1, ref currentRowNumber, tc, ref currentRow);

            AddDataRowsToXamlTable(dataTable, fontSize, table1, ref currentRowNumber, tc, ref currentRow);
            return flowDoc;
        }

        public static FlowDocument CreateXamlTableFromDataTable(string tableTitle, DataTable dataTable, Typeface font, int fontSize, CellHighlighting highlighting, int minColumnWidth = 50)
        {
            FlowDocument flowDoc = new FlowDocument();
            Table table1 = new Table();
            flowDoc.Blocks.Add(table1);

            int currentRowNumber = 0;
            ThicknessConverter tc;
            int numberOfColumns;
            TableRow currentRow = new TableRow();


            SetTableAndColumnProperties(dataTable, fontSize, minColumnWidth, font, table1, out tc, out numberOfColumns);

            if (tableTitle != "")
                AddHeaderRowToXamlTable(ref currentRow, tableTitle, fontSize, table1, ref currentRowNumber, numberOfColumns);

            AddColmnHeaderRowToXamlTable(dataTable, fontSize, table1, ref currentRowNumber, tc, ref currentRow);

            AddDataRowsToXamlTable(dataTable, fontSize, table1, ref currentRowNumber, tc, ref currentRow, highlighting);

            return flowDoc;
        }

        public static FlowDocument CreateXamlTableFromDataTable(string tableTitle, DataTable dataTable, Typeface font, int fontSize, int minColumnWidth = 50)
        {
            FlowDocument flowDoc = new FlowDocument();
            Table table1 = new Table();
            flowDoc.Blocks.Add(table1);

            int currentRowNumber = 0;
            ThicknessConverter tc;
            int numberOfColumns;
            TableRow currentRow = new TableRow();


            SetTableAndColumnProperties(dataTable, fontSize, minColumnWidth, font, table1, out tc, out numberOfColumns);

            if (tableTitle != "")
                AddHeaderRowToXamlTable(ref currentRow, tableTitle, fontSize, table1, ref currentRowNumber, numberOfColumns);

            AddColmnHeaderRowToXamlTable(dataTable, fontSize, table1, ref currentRowNumber, tc, ref currentRow);

            AddDataRowsToXamlTable(dataTable, fontSize, table1, ref currentRowNumber, tc, ref currentRow);

            return flowDoc;
        }
        #endregion

        #region -- Misc Report Info ---------------------------------------------------
        public FlowDocument BuildLoadTestSettingsAsFlowDocument(int runId, string propertiesTemplate, string scenariosTemplate)
        {
            string finalText = "";
            using (StreamReader sr = new StreamReader(propertiesTemplate))
            {
                string str = sr.ReadToEnd();
                finalText = AddRunSettings(str, runId);
            }

            using (StreamReader sr = new StreamReader(scenariosTemplate))
            {
                string str = sr.ReadToEnd();
                finalText += AddScenarios(str, runId);
            }

            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
            MemoryStream ms = new MemoryStream(encoding.GetBytes(finalText));

            FlowDocument flowDoc = new FlowDocument();
            TextRange text = new TextRange(flowDoc.ContentStart, flowDoc.ContentEnd);
            text.Load(ms, DataFormats.Xaml);
            return flowDoc;
        }

        private string AddRunSettings(string sIn, int runId)
        {
            string sBody = sIn.Substring(0, sIn.Length - ("</Section>").Length);

            Dictionary<string, string> _dict = re.listOfRuns[runId].runConfiguration;
            foreach (KeyValuePair<string, string> kvp in _dict)
            {
                sBody = sBody.Replace("{{" + kvp.Key + "}}", kvp.Value);
            }

            return sBody;
        }

        private string AddScenarios(string sIn, int runId)
        {
            // This part separates the template so that we have only one header and footer regardless of
            // how many times we add the template to the main string
            int iLen = sIn.IndexOf(">");
            string sHeader = sIn.Substring(0, iLen + 1);
            string sBody = sIn.Substring(iLen + 1);
            sBody = sBody.Substring(0, sBody.Length - ("</Section>").Length);

            StringBuilder sb = new StringBuilder();

            for (int iScenarioCount = 1; iScenarioCount <= re.listOfRuns[runId].scenarios.Count; iScenarioCount++)
            {
                Dictionary<string, string> _dict = re.listOfRuns[runId].scenarios.ElementAt(iScenarioCount - 1).Value;

                sb.Append(sBody);

                sb = sb.Replace("{{ScenarioName}}", _dict.ElementAt(0).Value);

                for (int x = 1; x < 12; x++)  // Get everything but the name and the test mix
                {
                    string sTemp = _dict.ElementAt(x).Value.Replace("\"", "");
                    sb = sb.Replace("{{" + _dict.ElementAt(x).Key + "}}", sTemp);
                }

                string str = _dict.ElementAt(12).Value;
                int a = 1;

                foreach (string substr in str.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries))
                {
                    sb = sb.Replace("{{TestCase}}" + a.ToString() + "a", substr);
                    a++;
                }

                while (a < 13)
                {
                    sb = sb.Replace("{{TestCase}}" + a.ToString() + "a", "");
                    a++;
                }
            }
            //sb.Insert(0, sHeader);
            sb.Append("</Section>");
            return sb.ToString();
        }

        public void AddDebugTimingInfoToReport(string debugTimingInfo)
        {

            List listx = new List();
            // Set the space between the markers and list content to 25 DIP.
            listx.MarkerOffset = 15;

            // Use uppercase Roman numerals.
            listx.MarkerStyle = TextMarkerStyle.Disc;
            // Start list numbering at 5.
            //listx.StartIndex = 5;

            foreach (string str in debugTimingInfo.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
            {
                Paragraph paragraph = new Paragraph();
                paragraph.Inlines.Add(new Bold(new Run(str.Substring(0, str.IndexOf(":") + 1))));
                paragraph.Inlines.Add(new Run(str.Substring(str.IndexOf(":") + 1)));

                ListItem liV = new ListItem(paragraph);
                listx.ListItems.Add(liV);
            }

            // Create a document and add this paragraph.
            fd.Blocks.Add(listx);
        }
        #endregion

        #region -- Report Utility Routines --------------------------------------------
        public static Paragraph AddSectionTitleToReport(string titleString)
        {
            // Create bolded text.
            Run run = new Run();
//            run.Text = "\r\n" + titleString;
            run.Text = titleString;

            // Add three parts of sentence to a paragraph, in order.
            Paragraph paragraph = new Paragraph();
            FontFamilyValueSerializer ffvs = new FontFamilyValueSerializer();
            //paragraph.FontFamily = ffvs.ConvertFromString("Segoe UI Light"
            paragraph.FontSize = 21.33;
            paragraph.TextDecorations = TextDecorations.Underline;
            paragraph.Inlines.Add(run);

            // Create a document and add this paragraph.
            return paragraph;
        }

        public static FlowDocument AddSectionTitleToReport(string titleString, Typeface font, int fontSize, bool addSeparatorLine)
        {
            FlowDocument _doc = new FlowDocument();
            
            Run run = new Run();
            run.Text = titleString;

            // Add three parts of sentence to a paragraph, in order.
            Paragraph paragraph = new Paragraph();
            paragraph.FontFamily = font.FontFamily;
            paragraph.FontSize = fontSize;
            paragraph.Inlines.Add(run);

            // Create a document and add this paragraph.

            return _doc;
        }

        public static Paragraph AddCommentLineToReport(string commentString, Color color, double fontSize = 12)
        {
            Run run = new Run();
            run.Foreground = new SolidColorBrush(color);
            run.Text = commentString;

            // Add three parts of sentence to a paragraph, in order.
            Paragraph paragraph = new Paragraph();
            paragraph.FontSize = fontSize;            
            paragraph.Inlines.Add(new Italic(run));

            // Create a document and add this paragraph.
            return paragraph;
        }

        public static FlowDocument AddSeparatorLineToReport()
        {
            MemoryStream ms =
               new MemoryStream(ASCIIEncoding.Default.GetBytes(@"{\pard\brdrb\brdrs\brdrw20\brsp2\par}"));
            FlowDocument fd = new FlowDocument();
            TextRange text = new TextRange(fd.ContentStart, fd.ContentEnd);
            text.Load(ms, DataFormats.Rtf);

            return fd;
        }
        #endregion

        #region -- Internal Utilities ---------------------------------------------------
        private static int GetLengthOfLongestEntryInColumn(ref DataTable table, int column, Typeface font, int fontSize, int minColumnWidth = 50, int maxColumnWidth = 350)
        {
            int iLongestLength = 0;
            int iLongestRow = 0;

            for(int x = 0; x < table.Rows.Count; x++)
            {
                DataRow row = table.Rows[x];                
                if(iLongestLength < row[column].ToString().Length)
                {
                    iLongestLength = row[column].ToString().Length;
                    iLongestRow = x;
                }
            }
            
            string str = table.Rows[iLongestRow][column].ToString();
            FormattedText _text = new FormattedText(str, System.Globalization.CultureInfo.CurrentCulture
                , FlowDirection.LeftToRight, font, fontSize, Brushes.White);
            double columnWidth = _text.Width;
            
            if (columnWidth < minColumnWidth)
                return minColumnWidth;
            else if (columnWidth > maxColumnWidth)
                return maxColumnWidth;
            else
                return (int)columnWidth;
        }

        private static void SetTableAndColumnProperties(DataTable dataTable, int fontSize, int minColumnWidth, Typeface font, Table table1, out ThicknessConverter tc, out int numberOfColumns)
        {
            // Set some global formatting properties for the table.
            tc = new ThicknessConverter();

            table1.CellSpacing = 0;
            table1.Background = Brushes.White;
            //table1.BorderBrush = Brushes.Black;
            //table1.BorderThickness = (Thickness)tc.ConvertFromString("0.0125in");

            // Create columns and add them to the table's Columns collection. 
            numberOfColumns = dataTable.Columns.Count;
            for (int x = 0; x < numberOfColumns; x++)
            {
                TableColumn col = new TableColumn();
                // Need to add a cushion to the text length to account for padding and margins. Trying a value of 8
                col.Width = new GridLength(8 + GetLengthOfLongestEntryInColumn(ref dataTable, x, font, fontSize, minColumnWidth));
                table1.Columns.Add(col);
            }
            table1.RowGroups.Add(new TableRowGroup());
        }

        //ThicknessConverter _tc = new ThicknessConverter();
        //Table myTable = new Table();
        //double cellSpacing;
        //SolidColorBrush tableBackgroundBrush = Brushes.White;
        //SolidColorBrush tableBorderBrush = Brushes.Black;
        
        //SolidColorBrush titleRowBackgroundBrush = Brushes.Wheat;
        //SolidColorBrush titleRowBorderBrush = Brushes.Black;
        //double titleRowFontSize;
        
        //FontWeight headerRowFontWeight = System.Windows.FontWeights.Bold;
        //double headerRowFontSize;
        //SolidColorBrush headerRowCellBorderBrush = Brushes.Black;
        ////FontWeight headerRowFontWeight = System.Windows.FontWeights.Bold;
        //SolidColorBrush headerRowCellBackgroundBrush = Brushes.Gainsboro;
        ////Thickness headerRowCellBorderThickness = (Thickness)_tc.ConvertFromString("1pt");
        //string headerRowCellBorderThickness = "1pt";
        //Thickness headerRowCellPadding = new Thickness(2);

        private static void SetTableAndColumnProperties(DataTable dataTable, int fontSize, int minColumnWidth, Typeface font, Table table1, out ThicknessConverter tc, out int numberOfColumns, List<int> columnWidths)
        {
            // Set some global formatting properties for the table.
            tc = new ThicknessConverter();

            table1.CellSpacing = 0;
            table1.Background = Brushes.White;
            table1.BorderBrush = Brushes.Black;

            // Create columns and add them to the table's Columns collection. 
            numberOfColumns = dataTable.Columns.Count;
            for (int x = 0; x < numberOfColumns; x++)
            {
                TableColumn col = new TableColumn();
                if( x < columnWidths.Count)
                {
                    if (columnWidths[x] == -1)
                        col.Width = new GridLength(8 + GetLengthOfLongestEntryInColumn(ref dataTable, x, font, fontSize, minColumnWidth));
                    else
                        col.Width = new GridLength(columnWidths[x]);
                }
                else
                {
                    col.Width = new GridLength(8 + GetLengthOfLongestEntryInColumn(ref dataTable, x, font, fontSize, minColumnWidth));
                }
                table1.Columns.Add(col);
            }
            // Create and add an empty TableRowGroup to hold the table's Rows.       
            table1.RowGroups.Add(new TableRowGroup());
        }

        private static void AddHeaderRowToXamlTable(ref TableRow currentRow, string tableTitle, int fontSize, Table table1, ref int currentRowNumber, int numberOfColumns)
        {
            // Add the first (title) row.
            table1.RowGroups[0].Rows.Add(new TableRow());

            // Alias the current working row for easy reference.
            currentRow = table1.RowGroups[0].Rows[currentRowNumber++];

            // Global formatting for the title row.
            currentRow.Background = Brushes.Wheat;
            currentRow.FontSize = fontSize + 4;
            currentRow.FontWeight = System.Windows.FontWeights.Bold;

            // Add the header row with content, 
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run(tableTitle))));

            currentRow.Cells[0].ColumnSpan = numberOfColumns;
            currentRow.Cells[0].BorderBrush = Brushes.Black;
            currentRow.Cells[0].TextAlignment = TextAlignment.Center;

            // Add a tiny row to separate the header from the table
            table1.RowGroups[0].Rows.Add(new TableRow());
            currentRow = table1.RowGroups[0].Rows[currentRowNumber++];
            currentRow.Background = Brushes.White;
            currentRow.FontSize = 4;

            // Add the header row with content, 
            currentRow.Cells.Add(new TableCell(new Paragraph(new Run(" "))));

            currentRow.Cells[0].ColumnSpan = numberOfColumns;
            currentRow.Cells[0].BorderBrush = Brushes.White;

        }

        private static void AddColmnHeaderRowToXamlTable(DataTable dataTable, int fontSize, Table table1, ref int currentRowNumber, ThicknessConverter tc, ref TableRow currentRow)
        {
            // Add the second (header) row.
            table1.RowGroups[0].Rows.Add(new TableRow());
            currentRow = table1.RowGroups[0].Rows[currentRowNumber++];

            // Global formatting for the header row.
            currentRow.FontSize = fontSize;
            currentRow.FontWeight = FontWeights.Bold;

            // Add cells with content to the second row.
            foreach (DataColumn column in dataTable.Columns)
            {
                TableCell cell1 = new TableCell(new Paragraph(new Run(column.ColumnName)));
                cell1.BorderBrush = Brushes.Black;
                cell1.Background = Brushes.Gainsboro;
                cell1.BorderThickness = (Thickness)tc.ConvertFromString("1pt");
                cell1.Padding = new Thickness(2); //(Thickness)tc.ConvertFromString("0.025in");
                currentRow.Cells.Add(cell1);
            }
        }

        private static void AddDataRowsToXamlTable(DataTable dataTable, int fontSize, Table table1, ref int currentRowNumber, ThicknessConverter tc, ref TableRow currentRow, CellHighlighting highlighting)
        {
            // Add the data.
            foreach (DataRow row in dataTable.Rows)
            {
                table1.RowGroups[0].Rows.Add(new TableRow());
                currentRow = table1.RowGroups[0].Rows[currentRowNumber++];

                // Global formatting for the row.
                currentRow.FontSize = fontSize;
                currentRow.FontWeight = FontWeights.Normal;
                for (int x = 0; x < dataTable.Columns.Count; x++)
                {
                    TableCell cell1 = new TableCell(new Paragraph(new Run(row[x].ToString())));
                    cell1.BorderBrush = Brushes.Black;
                    if (row[x] != System.DBNull.Value)
                    {
                        if (dataTable.Columns[x].DataType == System.Type.GetType("System.Int32")
                            && dataTable.Columns[x].ColumnName != "Id"
                            && dataTable.Columns[x].ColumnName != "Qty")
                        {
                            cell1.Background = new SolidColorBrush(highlighting.GetCellHighlightColor((int)row[x]));
                        }
                        else if (dataTable.Columns[x].DataType == System.Type.GetType("System.Decimal"))
                        {
                            cell1.Background = new SolidColorBrush(highlighting.GetCellHighlightColor((decimal)row[x]));
                        }
                        else
                        {
                            cell1.Background = Brushes.White;
                        }
                    }
                    else
                    {
                        cell1.Background = Brushes.White;
                    }
                    cell1.BorderThickness = (Thickness)tc.ConvertFromString("1pt");
                    cell1.Padding = new Thickness(2); //(Thickness)tc.ConvertFromString("0.025in");
                    currentRow.Cells.Add(cell1);
                }

                // Bold the first cell.
                //currentRow.Cells[0].FontWeight = FontWeights.Bold;
            }
        }

        private static void AddDataRowsToXamlTable(DataTable dataTable, int fontSize, Table table1, ref int currentRowNumber, ThicknessConverter tc, ref TableRow currentRow)
        {
            // Add the data.
            foreach (DataRow row in dataTable.Rows)
            {
                table1.RowGroups[0].Rows.Add(new TableRow());
                currentRow = table1.RowGroups[0].Rows[currentRowNumber++];

                // Global formatting for the row.
                currentRow.FontSize = fontSize;
                currentRow.FontWeight = FontWeights.Normal;
                for (int x = 0; x < dataTable.Columns.Count; x++)
                {
                    TableCell cell1 = new TableCell(new Paragraph(new Run(row[x].ToString())));
                    cell1.BorderBrush = Brushes.Black;
                    cell1.Background = (currentRowNumber % 2 == 0) ? Brushes.Cyan : Brushes.White;
                    cell1.BorderThickness = (Thickness)tc.ConvertFromString("1pt");
                    cell1.Padding = new Thickness(2); //(Thickness)tc.ConvertFromString("0.025in");
                    currentRow.Cells.Add(cell1);
                }

                // Bold the first cell.
                //currentRow.Cells[0].FontWeight = FontWeights.Bold;
            }
        }
        #endregion
    }

    public class CellHighlighting
    {
        public double threshold1 { get; set; }
        public double threshold2 { get; set; }
        public double threshold3 { get; set; }
        public double threshold4 { get; set; }

        public Color thresholdColor1 { get; set; }
        public Color thresholdColor2 { get; set; }
        public Color thresholdColor3 { get; set; }
        public Color thresholdColor4 { get; set; }
        public Color thresholdColor5 { get; set; }

        public CellHighlighting() 
        { 
            //Set defaults in case they are not set by the app
            threshold1 = 0.01;
            threshold2 = 0.1;
            threshold3 = 1.0;
            threshold4 = -1;

            thresholdColor1 = Colors.Green;
            thresholdColor2 = Colors.LightGreen;
            thresholdColor3 = Colors.Yellow;
            thresholdColor4 = Colors.Orange;
            thresholdColor5 = Colors.Red;
        }
        
        public void SetThresholdValues(double threshold1Value, double threshold2Value, double threshold3Value = -1, double threshold4Value = -1)
        {
            threshold1 = threshold1Value;
            threshold2 = threshold2Value;
            threshold3 = threshold3Value;
            threshold4 = threshold4Value;
        }

        public void SetThresholdColors(Color threshold1Color, Color threshold2Color, Color threshold3Color, Color threshold4Color, Color threshold5Color)
        {
            thresholdColor1 = threshold1Color;
            thresholdColor2 = threshold2Color;
            thresholdColor3 = threshold3Color;
            thresholdColor4 = threshold4Color;
            thresholdColor5 = threshold5Color;
        }

        public int GetThresholdAsInt(double value)
        {
            return Convert.ToInt32(Math.Round(value));
        }

        public decimal GetThresholdAsDecimal(double value)
        {
            decimal retVal = Convert.ToDecimal(value);
            return retVal;
        }

        public Color GetCellHighlightColor(double value)
        {
            if (value <= threshold1)
            {
                return thresholdColor1;
            }
            else if (value <= threshold2)
            {
                return thresholdColor2;
            }
            else if (threshold3 == -1) // only have three colors
            {
                return thresholdColor3;
            }
            else if (value <= threshold3)
            {
                return thresholdColor3;
            }
            else if (threshold4 == -1) // only have 4 colors
            {
                return thresholdColor4;
            }
            else if (value <= threshold4)
            {
                return thresholdColor4;
            }
            else
            {
                return thresholdColor5;
            }
        }

        public Color GetCellHighlightColor(decimal value)
        {
            if (value <= GetThresholdAsDecimal(threshold1))
            {
                return thresholdColor1;
            }
            else if (value <= GetThresholdAsDecimal(threshold2))
            {
                return thresholdColor2;
            }
            else if (GetThresholdAsDecimal(threshold3) == -1) // only have three colors
            {
                return thresholdColor3;
            }
            else if (value <= GetThresholdAsDecimal(threshold4))
            {
                return thresholdColor3;
            }
            else if (GetThresholdAsDecimal(threshold4) == -1) // only have 4 colors
            {
                return thresholdColor4;
            }
            else if (value <= GetThresholdAsDecimal(threshold4))
            {
                return thresholdColor4;
            }
            else
            {
                return thresholdColor5;
            }
        }

        public Color GetCellHighlightColor(int value)
        {
            if (value <= threshold1)
            {
                return thresholdColor1;
            }
            else if (value <= threshold2)
            {
                return thresholdColor2;
            }
            else if (threshold3 == -1) // only have three colors
            {
                return thresholdColor3;
            }
            else if (value <= threshold3)
            {
                return thresholdColor3;
            }
            else if (threshold4 == -1) // only have 4 colors
            {
                return thresholdColor4;
            }
            else if (value <= threshold4)
            {
                return thresholdColor4;
            }
            else
            {
                return thresholdColor5;
            }
        }

        public void ReadHighlightSettingsFromXmlFile(string XmlFileName)
        {
            try
            {
                XmlDocument xDoc = new XmlDocument();
                xDoc.Load(XmlFileName);
                foreach (XmlNode xNode in xDoc.GetElementsByTagName("CellHighlighting"))
                {
                    foreach (XmlNode xChild in xNode.ChildNodes)
                    {
                        switch(xChild.Name)
                        {
                            case "CellHighlightColor1":
                                this.thresholdColor1 = (Color)ColorConverter.ConvertFromString(xChild.Attributes["color"].Value);
                                break;

                            case "CellHighlightColor2":
                                this.thresholdColor2 = (Color)ColorConverter.ConvertFromString(xChild.Attributes["color"].Value);
                                break;

                            case "CellHighlightColor3":
                                this.thresholdColor3 = (Color)ColorConverter.ConvertFromString(xChild.Attributes["color"].Value);
                                break;

                            case "CellHighlightColor4":
                                this.thresholdColor4 = (Color)ColorConverter.ConvertFromString(xChild.Attributes["color"].Value);
                                break;

                            case "CellHighlightColor5":
                                this.thresholdColor5 = (Color)ColorConverter.ConvertFromString(xChild.Attributes["color"].Value);
                                break;

                            case "CellThresholdValue1":
                                this.threshold1 = Convert.ToDouble(xChild.Attributes["value"].Value);
                                break;

                            case "CellThresholdValue2":
                                this.threshold2 = Convert.ToDouble(xChild.Attributes["value"].Value);
                                break;

                            case "CellThresholdValue3":
                                this.threshold3 = Convert.ToDouble(xChild.Attributes["value"].Value);
                                break;

                            case "CellThresholdValue4":
                                this.threshold4 = Convert.ToDouble(xChild.Attributes["value"].Value);
                                break;
                        }
                    }
                }
            }
            catch (XmlException ex)
            {
                throw new XmlException("Exception Reading Highlight Rules", ex); 
            }
        }
    }
}
